home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / PNGLIB06.ZIP / PNGREAD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-01  |  19.1 KB  |  599 lines

  1.  
  2. /* pngread.c - read a png file
  3.  
  4.    pnglib version 0.6
  5.    For conditions of distribution and use, see copyright notice in png.h
  6.    Copyright (c) 1995 Guy Eric Schalnat, Group 42, Inc.
  7.    May 1, 1995
  8.    */
  9.  
  10. #define PNG_INTERNAL
  11. #include "png.h"
  12.  
  13. /* initialize png structure for reading, and allocate any memory needed */
  14. void
  15. png_read_init(png_struct *png_ptr)
  16. {
  17.    jmp_buf tmp_jmp;
  18.  
  19.    memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
  20.    memset(png_ptr, 0, sizeof (png_struct));
  21.    memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
  22.  
  23.    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
  24.    png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
  25.    png_ptr->zstream = &(png_ptr->zstream_struct);
  26.    png_ptr->zstream->zalloc = png_zalloc;
  27.    png_ptr->zstream->zfree = png_zfree;
  28.    png_ptr->zstream->opaque = png_ptr;
  29.    inflateInit(png_ptr->zstream);
  30.    png_ptr->zstream->next_out = png_ptr->zbuf;
  31.    png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
  32. }
  33.  
  34. /* read the information before the actual image data. */
  35. void
  36. png_read_info(png_struct *png_ptr, png_info *info)
  37. {
  38.    png_byte chunk_start[8];
  39.    png_uint_32 length;
  40.  
  41.    png_read_data(png_ptr, chunk_start, 8);
  42.    if (memcmp(chunk_start, png_sig, 8))
  43.       png_error(png_ptr, "Not a Png File");
  44.  
  45.    while (1)
  46.    {
  47.       png_uint_32 crc;
  48.  
  49.       png_read_data(png_ptr, chunk_start, 8);
  50.       length = png_get_uint_32(chunk_start);
  51.       png_reset_crc(png_ptr);
  52.       png_calculate_crc(png_ptr, chunk_start + 4, 4);
  53.       if (!memcmp(chunk_start + 4, png_IHDR, 4))
  54.       {
  55.          if (png_ptr->mode != PNG_BEFORE_IHDR)
  56.             png_error(png_ptr, "Out of Place IHDR");
  57.  
  58.          png_handle_IHDR(png_ptr, info, length);
  59.          png_ptr->mode = PNG_HAVE_IHDR;
  60.       }
  61.       else if (!memcmp(chunk_start + 4, png_PLTE, 4))
  62.       {
  63.          if (png_ptr->mode != PNG_HAVE_IHDR)
  64.             png_error(png_ptr, "Missing IHDR");
  65.  
  66.          png_handle_PLTE(png_ptr, info, length);
  67.          png_ptr->mode = PNG_HAVE_PLTE;
  68.       }
  69.       else if (!memcmp(chunk_start + 4, png_gAMA, 4))
  70.       {
  71.          if (png_ptr->mode != PNG_HAVE_IHDR)
  72.             png_error(png_ptr, "Out of Place PLTE");
  73.  
  74.          png_handle_gAMA(png_ptr, info, length);
  75.       }
  76.       else if (!memcmp(chunk_start + 4, png_sBIT, 4))
  77.       {
  78.          if (png_ptr->mode != PNG_HAVE_IHDR)
  79.             png_error(png_ptr, "Out of Place sBIT");
  80.  
  81.          png_handle_sBIT(png_ptr, info, length);
  82.       }
  83.       else if (!memcmp(chunk_start + 4, png_cHRM, 4))
  84.       {
  85.          if (png_ptr->mode != PNG_HAVE_IHDR)
  86.             png_error(png_ptr, "Out of Place cHRM");
  87.  
  88.          png_handle_cHRM(png_ptr, info, length);
  89.       }
  90.       else if (!memcmp(chunk_start + 4, png_tRNS, 4))
  91.       {
  92.          if (png_ptr->mode != PNG_HAVE_IHDR &&
  93.             png_ptr->mode != PNG_HAVE_PLTE)
  94.             png_error(png_ptr, "Out of Place tRNS");
  95.  
  96.          png_handle_tRNS(png_ptr, info, length);
  97.       }
  98.       else if (!memcmp(chunk_start + 4, png_bKGD, 4))
  99.       {
  100.          if (png_ptr->mode != PNG_HAVE_IHDR &&
  101.             png_ptr->mode != PNG_HAVE_PLTE)
  102.             png_error(png_ptr, "Out of Place bKGD");
  103.  
  104.          png_handle_bKGD(png_ptr, info, length);
  105.       }
  106.       else if (!memcmp(chunk_start + 4, png_hIST, 4))
  107.       {
  108.          if (png_ptr->mode != PNG_HAVE_PLTE)
  109.             png_error(png_ptr, "Out of Place hIST");
  110.  
  111.          png_handle_hIST(png_ptr, info, length);
  112.       }
  113.       else if (!memcmp(chunk_start + 4, png_IDAT, 4))
  114.       {
  115.          png_ptr->idat_size = length;
  116.          png_ptr->mode = PNG_HAVE_IDAT;
  117.          break;
  118.       }
  119.       else if (!memcmp(chunk_start + 4, png_pHYs, 4))
  120.       {
  121.          if (png_ptr->mode != PNG_HAVE_IHDR &&
  122.             png_ptr->mode != PNG_HAVE_PLTE)
  123.             png_error(png_ptr, "Out of Place pHYs");
  124.  
  125.          png_handle_pHYs(png_ptr, info, length);
  126.       }
  127.       else if (!memcmp(chunk_start + 4, png_oFFs, 4))
  128.       {
  129.          if (png_ptr->mode != PNG_HAVE_IHDR &&
  130.             png_ptr->mode != PNG_HAVE_PLTE)
  131.             png_error(png_ptr, "Out of Place oFFs");
  132.  
  133.          png_handle_oFFs(png_ptr, info, length);
  134.       }
  135.       else if (!memcmp(chunk_start + 4, png_tIME, 4))
  136.       {
  137.          if (png_ptr->mode == PNG_BEFORE_IHDR ||
  138.             png_ptr->mode == PNG_AFTER_IEND)
  139.             png_error(png_ptr, "Out of Place tIME");
  140.  
  141.          png_handle_tIME(png_ptr, info, length);
  142.       }
  143.       else if (!memcmp(chunk_start + 4, png_tEXt, 4))
  144.       {
  145.          if (png_ptr->mode == PNG_BEFORE_IHDR ||
  146.             png_ptr->mode == PNG_AFTER_IEND)
  147.             png_error(png_ptr, "Out of Place tEXt");
  148.  
  149.          png_handle_tEXt(png_ptr, info, length);
  150.       }
  151.       else if (!memcmp(chunk_start + 4, png_zTXt, 4))
  152.       {
  153.          if (png_ptr->mode == PNG_BEFORE_IHDR ||
  154.             png_ptr->mode == PNG_AFTER_IEND)
  155.             png_error(png_ptr, "Out of Place zTXt");
  156.  
  157.          png_handle_zTXt(png_ptr, info, length);
  158.       }
  159.       else if (!memcmp(chunk_start + 4, png_IEND, 4))
  160.       {
  161.          png_error(png_ptr, "No Image in File");
  162.       }
  163.       else
  164.       {
  165.          if (isupper(chunk_start[4]))
  166.             png_error(png_ptr, "Unknown Critical Chunk");
  167.  
  168.          png_crc_skip(png_ptr, length);
  169.       }
  170.       png_read_data(png_ptr, chunk_start, 4);
  171.       crc = png_get_uint_32(chunk_start);
  172.       if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
  173.          (png_ptr->crc & 0xffffffffL))
  174.          png_error(png_ptr, "Bad CRC value");
  175.    }
  176. }
  177.  
  178. /* initialize palette, background, etc, after transformations
  179.    are set, but before any reading takes place.  This allows
  180.    the user to obtail a gamma corrected palette, for example.
  181.    If the user doesn't call this, we will do it ourselves. */
  182. void
  183. png_start_read_image(png_struct *png_ptr)
  184. {
  185.    png_read_start_row(png_ptr);
  186. }
  187.  
  188. void
  189. png_read_row(png_struct *png_ptr, png_byte *row, png_byte *dsp_row)
  190. {
  191.    int ret;
  192.  
  193.    if (!(png_ptr->row_init))
  194.       png_read_start_row(png_ptr);
  195.  
  196.    /* if interlaced and we do not need a new row, combine row and return */
  197.    if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
  198.    {
  199.       switch (png_ptr->pass)
  200.       {
  201.          case 0:
  202.             if (png_ptr->row_number & 7)
  203.             {
  204.                if (dsp_row)
  205.                   png_combine_row(png_ptr, dsp_row, row,
  206.                      png_pass_dsp_mask[png_ptr->pass]);
  207.                png_read_finish_row(png_ptr);
  208.                return;
  209.             }
  210.             break;
  211.          case 1:
  212.             if ((png_ptr->row_number & 7) || png_ptr->width < 5)
  213.             {
  214.                if (dsp_row)
  215.                   png_combine_row(png_ptr, dsp_row, row,
  216.                      png_pass_dsp_mask[png_ptr->pass]);
  217.                png_read_finish_row(png_ptr);
  218.                return;
  219.             }
  220.             break;
  221.          case 2:
  222.             if ((png_ptr->row_number & 7) != 4)
  223.             {
  224.                if (dsp_row && (png_ptr->row_number & 4))
  225.                   png_combine_row(png_ptr, dsp_row, row,
  226.                      png_pass_dsp_mask[png_ptr->pass]);
  227.                png_read_finish_row(png_ptr);
  228.                return;
  229.             }
  230.             break;
  231.          case 3:
  232.             if ((png_ptr->row_number & 3) || png_ptr->width < 3)
  233.             {
  234.                if (dsp_row)
  235.                   png_combine_row(png_ptr, dsp_row, row,
  236.                      png_pass_dsp_mask[png_ptr->pass]);
  237.                png_read_finish_row(png_ptr);
  238.                return;
  239.             }
  240.             break;
  241.          case 4:
  242.             if ((png_ptr->row_number & 3) != 2)
  243.             {
  244.                if (dsp_row && (png_ptr->row_number & 2))
  245.                   png_combine_row(png_ptr, dsp_row, row,
  246.                      png_pass_dsp_mask[png_ptr->pass]);
  247.                png_read_finish_row(png_ptr);
  248.                return;
  249.             }
  250.             break;
  251.          case 5:
  252.             if ((png_ptr->row_number & 1) || png_ptr->width < 2)
  253.             {
  254.                if (dsp_row)
  255.                   png_combine_row(png_ptr, dsp_row, row,
  256.                      png_pass_dsp_mask[png_ptr->pass]);
  257.                png_read_finish_row(png_ptr);
  258.                return;
  259.             }
  260.             break;
  261.          case 6:
  262.             if (!(png_ptr->row_number & 1))
  263.             {
  264.                png_read_finish_row(png_ptr);
  265.                return;
  266.             }
  267.             break;
  268.       }
  269.    }
  270.  
  271.    if (png_ptr->mode != PNG_HAVE_IDAT)
  272.       png_error(png_ptr, "invalid attempt to read row data");
  273.  
  274.    png_ptr->zstream->next_out = png_ptr->row_buf;
  275.    png_ptr->zstream->avail_out = (uInt)png_ptr->irowbytes;
  276.    do
  277.    {
  278.       if (!(png_ptr->zstream->avail_in))
  279.       {
  280.          while (!png_ptr->idat_size)
  281.          {
  282.             png_byte buf[4];
  283.             png_uint_32 crc;
  284.  
  285.             png_read_data(png_ptr, buf, 4);
  286.             crc = png_get_uint_32(buf);
  287.             if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
  288.                (png_ptr->crc & 0xffffffffL))
  289.                png_error(png_ptr, "Bad CRC value");
  290.  
  291.             png_read_data(png_ptr, buf, 4);
  292.             png_ptr->idat_size = png_get_uint_32(buf);
  293.             png_reset_crc(png_ptr);
  294.  
  295.             png_crc_read(png_ptr, buf, 4);
  296.             if (memcmp(buf, png_IDAT, 4))
  297.                png_error(png_ptr, "Not enough image data");
  298.  
  299.          }
  300.          png_ptr->zstream->avail_in = (uInt)png_ptr->zbuf_size;
  301.          png_ptr->zstream->next_in = png_ptr->zbuf;
  302.          if (png_ptr->zbuf_size > png_ptr->idat_size)
  303.             png_ptr->zstream->avail_in = (uInt)png_ptr->idat_size;
  304.          png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream->avail_in);
  305.          png_ptr->idat_size -= png_ptr->zstream->avail_in;
  306.       }
  307.       ret = inflate(png_ptr->zstream, Z_PARTIAL_FLUSH);
  308.       if (ret == Z_STREAM_END)
  309.       {
  310.          if (png_ptr->zstream->avail_out || png_ptr->zstream->avail_in ||
  311.             png_ptr->idat_size)
  312.             png_error(png_ptr, "Extra compressed data");
  313.          png_ptr->mode = PNG_AT_LAST_IDAT;
  314.          break;
  315.       }
  316.       if (ret != Z_OK)
  317.          png_error(png_ptr, "Compression Error");
  318.  
  319.    } while (png_ptr->zstream->avail_out);
  320.  
  321.    png_ptr->row_info.color_type = png_ptr->color_type;
  322.    png_ptr->row_info.width = png_ptr->iwidth;
  323.    png_ptr->row_info.channels = png_ptr->channels;
  324.    png_ptr->row_info.bit_depth = png_ptr->bit_depth;
  325.    png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
  326.    png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
  327.       (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
  328.  
  329.    if (png_ptr->row_buf[0])
  330.       png_read_filter_row(&(png_ptr->row_info),
  331.          png_ptr->row_buf + 1, png_ptr->prev_row + 1,
  332.          (int)(png_ptr->row_buf[0]));
  333.  
  334.    memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1);
  335.  
  336.    if (png_ptr->transformations)
  337.       png_do_read_transformations(png_ptr);
  338.  
  339.    /* blow up interlaced rows to full size */
  340.    if (png_ptr->interlaced &&
  341.       (png_ptr->transformations & PNG_INTERLACE))
  342.    {
  343.       if (png_ptr->pass < 6)
  344.          png_do_read_interlace(&(png_ptr->row_info),
  345.             png_ptr->row_buf + 1, png_ptr->pass);
  346.  
  347.       if (dsp_row)
  348.          png_combine_row(png_ptr, dsp_row, row,
  349.             png_pass_dsp_mask[png_ptr->pass]);
  350.       if (row)
  351.          png_combine_row(png_ptr, row, row,
  352.             png_pass_mask[png_ptr->pass]);
  353.    }
  354.    else
  355.    {
  356.       if (row)
  357.          png_combine_row(png_ptr, row, row, 0xff);
  358.       if (dsp_row)
  359.          png_combine_row(png_ptr, dsp_row, dsp_row, 0xff);
  360.    }
  361.    png_read_finish_row(png_ptr);
  362. }
  363.  
  364. /* read a one or more rows of image data.   If the image is interlaced,
  365.    and png_set_interlace_handling() has been called, the rows need to
  366.    to contain the contents of the rows from the previous pass.  If
  367.    the image has alpha or transparency, and png_handle_alpha() has been
  368.    called, the rows contents must be initialized to the contents of the
  369.    screen.  row holds the actual image, and pixels are placed in it
  370.    as they arrive.  If the image is displayed after each pass, it will
  371.    appear to "sparkle" in.  display_row can be used to display a
  372.    "chunky" progressive image, with finer detail added as it becomes
  373.    available.  If you do not want this "chunky" display, you may pass
  374.    NULL for display_rows.  If you do not want the sparkle display, and
  375.    you have not called png_handle_alpha(), you may pass NULL for rows.
  376.    If you have called png_handle_alpha(), and the image has either an
  377.    alpha channel or a transparency chunk, you must provide a buffer for
  378.    rows.  In this case, you do not have to provide a display_rows buffer
  379.    also, but you may.  If the image is not interlaced, or if you have
  380.    not called png_set_interlace_handling(), the display_row buffer will
  381.    be ignored, so pass NULL to it. */
  382. void
  383. png_read_rows(png_struct *png_ptr, png_byte **row,
  384.    png_byte **display_row, png_uint_32 num_rows)
  385. {
  386.    png_uint_32 i;
  387.    png_byte **rp;
  388.    png_byte **dp;
  389.  
  390.    rp = row;
  391.    dp = display_row;
  392.    for (i = 0; i < num_rows; i++)
  393.    {
  394.       png_read_row(png_ptr, *rp, *dp);
  395.       if (row)
  396.          rp++;
  397.       if (display_row)
  398.          dp++;
  399.    }
  400. }
  401.  
  402. /* read the image.  If the image has an alpha channel or a transparency
  403.    chunk, and you have called png_handle_alpha(), you will need to
  404.    initialize the image to the current image that png will be overlaying.
  405.    Note that png_set_interlace_handling() has no effect on this call.
  406.    You only need to call this function once.  If you desire to have
  407.    an image for each pass of a interlaced image, use png_read_rows() */
  408. void
  409. png_read_image(png_struct *png_ptr, png_byte **image)
  410. {
  411.    png_uint_32 i;
  412.    int pass, j;
  413.    png_byte **rp;
  414.  
  415.    pass = png_set_interlace_handling(png_ptr);
  416.    for (j = 0; j < pass; j++)
  417.    {
  418.       rp = image;
  419.       for (i = 0; i < png_ptr->height; i++)
  420.       {
  421.          png_read_row(png_ptr, *rp, NULL);
  422.          rp++;
  423.       }
  424.    }
  425. }
  426.  
  427. /* read the end of the png file.  Will not read past the end of the
  428.    file, will verify the end is accurate, and will read any comments
  429.    or time information at the end of the file, if info is not NULL. */
  430. void
  431. png_read_end(png_struct *png_ptr, png_info *info)
  432. {
  433.    png_byte chunk_start[8];
  434.    png_uint_32 length;
  435.    png_uint_32 crc;
  436.  
  437.    png_read_data(png_ptr, chunk_start, 4);
  438.    crc = png_get_uint_32(chunk_start);
  439.    if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
  440.       (png_ptr->crc & 0xffffffffL))
  441.       png_error(png_ptr, "Bad CRC value");
  442.  
  443.    do
  444.    {
  445.       png_read_data(png_ptr, chunk_start, 8);
  446.       length = png_get_uint_32(chunk_start);
  447.       png_reset_crc(png_ptr);
  448.       png_calculate_crc(png_ptr, chunk_start + 4, 4);
  449.  
  450.       if (!memcmp(chunk_start + 4, png_IHDR, 4))
  451.       {
  452.          png_error(png_ptr, "invalid chunk after IDAT");
  453.       }
  454.       else if (!memcmp(chunk_start + 4, png_PLTE, 4))
  455.       {
  456.          png_error(png_ptr, "invalid chunk after IDAT");
  457.       }
  458.       else if (!memcmp(chunk_start + 4, png_gAMA, 4))
  459.       {
  460.          png_error(png_ptr, "invalid chunk after IDAT");
  461.       }
  462.       else if (!memcmp(chunk_start + 4, png_sBIT, 4))
  463.       {
  464.          png_error(png_ptr, "invalid chunk after IDAT");
  465.       }
  466.       else if (!memcmp(chunk_start + 4, png_cHRM, 4))
  467.       {
  468.          png_error(png_ptr, "invalid chunk after IDAT");
  469.       }
  470.       else if (!memcmp(chunk_start + 4, png_tRNS, 4))
  471.       {
  472.          png_error(png_ptr, "invalid chunk after IDAT");
  473.       }
  474.       else if (!memcmp(chunk_start + 4, png_bKGD, 4))
  475.       {
  476.          png_error(png_ptr, "invalid chunk after IDAT");
  477.       }
  478.       else if (!memcmp(chunk_start + 4, png_hIST, 4))
  479.       {
  480.          png_error(png_ptr, "invalid chunk after IDAT");
  481.       }
  482.       else if (!memcmp(chunk_start + 4, png_IDAT, 4))
  483.       {
  484.          if (length > 0 || png_ptr->mode != PNG_AT_LAST_IDAT)
  485.             png_error(png_ptr, "too many IDAT's found");
  486.       }
  487.       else if (!memcmp(chunk_start + 4, png_pHYs, 4))
  488.       {
  489.          png_error(png_ptr, "invalid chunk after IDAT");
  490.       }
  491.       else if (!memcmp(chunk_start + 4, png_oFFs, 4))
  492.       {
  493.          png_error(png_ptr, "invalid chunk after IDAT");
  494.       }
  495.       else if (!memcmp(chunk_start + 4, png_tIME, 4))
  496.       {
  497.          if (png_ptr->mode == PNG_BEFORE_IHDR ||
  498.             png_ptr->mode == PNG_AFTER_IEND)
  499.             png_error(png_ptr, "Out of Place tIME");
  500.  
  501.          if (info)
  502.             png_handle_tIME(png_ptr, info, length);
  503.          else
  504.             png_crc_skip(png_ptr, length);
  505.       }
  506.       else if (!memcmp(chunk_start + 4, png_tEXt, 4))
  507.       {
  508.          if (png_ptr->mode == PNG_BEFORE_IHDR ||
  509.             png_ptr->mode == PNG_AFTER_IEND)
  510.             png_error(png_ptr, "Out of Place tEXt");
  511.  
  512.          if (info)
  513.             png_handle_tEXt(png_ptr, info, length);
  514.          else
  515.             png_crc_skip(png_ptr, length);
  516.       }
  517.       else if (!memcmp(chunk_start + 4, png_zTXt, 4))
  518.       {
  519.          if (png_ptr->mode == PNG_BEFORE_IHDR ||
  520.             png_ptr->mode == PNG_AFTER_IEND)
  521.             png_error(png_ptr, "Out of Place zTXt");
  522.  
  523.          if (info)
  524.             png_handle_zTXt(png_ptr, info, length);
  525.          else
  526.             png_crc_skip(png_ptr, length);
  527.       }
  528.       else if (!memcmp(chunk_start + 4, png_IEND, 4))
  529.       {
  530.          png_ptr->mode = PNG_AFTER_IEND;
  531.       }
  532.       else
  533.       {
  534.          if (isupper(chunk_start[4]))
  535.             png_error(png_ptr, "Unknown Critical Chunk");
  536.  
  537.          png_crc_skip(png_ptr, length);
  538.       }
  539.       png_read_data(png_ptr, chunk_start, 4);
  540.       crc = png_get_uint_32(chunk_start);
  541.       if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
  542.          (png_ptr->crc & 0xffffffffL))
  543.          png_error(png_ptr, "Bad CRC value");
  544.       if (png_ptr->mode == PNG_AT_LAST_IDAT)
  545.          png_ptr->mode = PNG_AFTER_IDAT;
  546.    } while (png_ptr->mode != PNG_AFTER_IEND);
  547. }
  548.  
  549. /* free all memory used by the read */
  550. void
  551. png_read_destroy(png_struct *png_ptr, png_info *info)
  552. {
  553.    int i;
  554.    jmp_buf tmp_jmp;
  555.  
  556.    if (info)
  557.    {
  558.       if (info->palette != png_ptr->palette)
  559.          png_free(png_ptr, info->palette);
  560.       if (info->trans != png_ptr->trans)
  561.          png_free(png_ptr, info->trans);
  562.       if (info->hist != png_ptr->hist)
  563.          png_free(png_ptr, info->hist);
  564.       for (i = 0; i < info->num_text; i++)
  565.       {
  566.          png_large_free(png_ptr, info->text[i].key);
  567.       }
  568.  
  569.       /* free stuff for transformations when I get them written */
  570.  
  571.       png_free(png_ptr, info->text);
  572.       memset(info, 0, sizeof(png_info));
  573.    }
  574.  
  575.    png_free(png_ptr, png_ptr->zbuf);
  576.    png_free(png_ptr, png_ptr->row_buf);
  577.    png_free(png_ptr, png_ptr->prev_row);
  578.    png_free(png_ptr, png_ptr->palette_lookup);
  579.    png_free(png_ptr, png_ptr->gamma_table);
  580.    if (png_ptr->gamma_16_table)
  581.    {
  582.       for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
  583.       {
  584.          png_free(png_ptr, png_ptr->gamma_16_table[i]);
  585.       }
  586.    }
  587.    png_free(png_ptr, png_ptr->gamma_16_table);
  588.    png_free(png_ptr, png_ptr->trans);
  589.    png_free(png_ptr, png_ptr->hist);
  590.  
  591.    inflateEnd(png_ptr->zstream);
  592.  
  593.    memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
  594.    memset(png_ptr, 0, sizeof (png_struct));
  595.    memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
  596. }
  597.  
  598.  
  599.